/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package serversocket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *
 * @author Leo
 */

/*
 * clase principal del servidor la cual es utilizada para recibir las peticiones del
 * cliente y realizar las operaciones que estos necesiten realizar, entre ellas iniciar
 * sesion, descargar o cargar un archivo
 */
public class Servicio implements Runnable {

    private ServerSocket servicio;
    private Socket socketServicio;
    private DataInputStream entrada;
    private DataOutputStream salida;
    private String ruta = "Archivos/";
    private FileInputStream archivo;
    private FileOutputStream archivoEntrada;
    private long tamano;
    private long cantidadDescargada;
    private ListaPersonas listaPersonas;
    private CargaDescargaPersonas carga = new CargaDescargaPersonas();

    public Servicio(ServerSocket servicio, Socket socketServicio, ListaPersonas listaPersonas) {
        this.servicio = servicio;
        this.socketServicio = socketServicio;
        this.listaPersonas = listaPersonas;
    }
    /*
     * metodo que es utilizado para verificar la clave y el nombre de usuario
     * y de esta forma permitirle o no iniciar sesion
     */
    public void conexionLogin() {
        try {
            String llego = entrada.readUTF();

            int j = 0;
            String[] campos = llego.split("\\+");
            while (j < campos.length) {
                j++;
            }
            String campoUsuario = campos[0];
            String campoClave = campos[1];

            int i = 0, tama = 0;
            boolean existe = false;
            tama = listaPersonas.getMisPersonas().size();
            for (i = 0; i < tama; i++) {
                if ((campoUsuario.compareTo(listaPersonas.getMisPersonas().get(i).getUsuario()) == 0)
                        && (campoClave.compareTo(listaPersonas.getMisPersonas().get(i).getClave()) == 0)) {
                    existe = true;
                    break;
                }
            }

            if (existe == true) {
                salida.writeUTF("true");
                int cont = 0;
                int cantidadArchivos = listaPersonas.getMisPersonas().get(i).getListaArchivos().size();
                String cadenaArchivos = "";
                while (cont < cantidadArchivos) {
                    cadenaArchivos += listaPersonas.getMisPersonas().get(i).getListaArchivos().get(cont).getNombreArchivo() + "/";
                    cont++;
                }
                salida.writeUTF(cadenaArchivos);
            } else {
                salida.writeUTF("false");
            }

            salida.close();
            entrada.close();
        } catch (IOException ex) {
            System.out.println("Algo se daño en login");
        }
    }
    /*
     * metodo que devuelve los archivos que ha cargado un usuario especifico
     */
    private String cadenaArchivosUsuario(String nombreUsuario) {
        int i = 0, tama = 0;
        boolean existe = false;
        tama = listaPersonas.getMisPersonas().size();
        for (i = 0; i < tama; i++) {
            if (nombreUsuario.compareTo(listaPersonas.getMisPersonas().get(i).getUsuario()) == 0) {
                existe = true;
                break;
            }
        }

        String cadenaArchivos = "";
        if (existe) {
            int cont = 0;
            int cantidadArchivos = listaPersonas.getMisPersonas().get(i).getListaArchivos().size();

            while (cont < cantidadArchivos) {
                cadenaArchivos += listaPersonas.getMisPersonas().get(i).getListaArchivos().get(cont).getNombreArchivo() + "/";
                cont++;
            }
            return cadenaArchivos;
        }
        return cadenaArchivos;
    }
    /*
     * metodo que devuelve la posicion de un usuario dentro de la lista de los usuarios del sistema
     */
    private int posicionUsuario(String nombreUsuario) {
        int i = 0, tama = 0;
        boolean existe = false;
        tama = listaPersonas.getMisPersonas().size();
        for (i = 0; i < tama; i++) {
            if (nombreUsuario.compareTo(listaPersonas.getMisPersonas().get(i).getUsuario()) == 0) {
                existe = true;
                break;
            }
        }
        if (existe) {
            return i;
        }
        return i;
    }
    /*
     * metodo que devuelve luego de ingresar el nombre del archivo y el nombre del usuario,
     * si un archivo lo tiene un usuario dentro de sus archivos cargados al servidor
     */
    private boolean existeArchivoCompleto(String nombrearchivo, String nombreusuario) {
        int i = 0, tama = 0, pos = 0;
        boolean existe = false;
        pos = posicionUsuario(nombreusuario);
        tama = listaPersonas.getMisPersonas().get(pos).getListaArchivos().size();
        for (i = 0; i < tama; i++) {
            if (nombrearchivo.compareTo(listaPersonas.getMisPersonas().get(pos).getListaArchivos().get(i).getNombreArchivo()) == 0) {
                existe = true;
                break;
            }
        }
        return existe;
    }
    /*
     * metodo que se encarga de enviar el archivo al cliente desde cero
     */
    private void descargarArchivo() {
        try {
            String nombrearchivo = entrada.readUTF();
            String nombreusuario = entrada.readUTF();
            boolean existe = existeArchivoCompleto(nombrearchivo, nombreusuario);
            salida.writeBoolean(existe);
            if (existe) {
                File f = new File(ruta + nombrearchivo);
                tamano = f.length();
                salida.writeLong(tamano);

                archivo = new FileInputStream(ruta + nombrearchivo);
                System.out.println("Iniciando transmision con" + String.valueOf(archivo.getChannel().size()) + " bytes");
                byte[] buffer = new byte[1024];
                int len;
                int total = 0;
                while ((len = archivo.read(buffer)) > 0) {
                    salida.write(buffer, 0, len);
                    total = total + len;
                }
                System.out.println("Fin de envio");
            }
        } catch (IOException e) {
            System.out.println("se cayo en la descarga");
        }
    }
    /*
     * metodo que se encarga de enviar un archivo al cliente desde un estado especifico
     */
    private void continuarDescargarArchivo() {
        try {
            String nombrearchivo = entrada.readUTF();
            String nombreusuario = entrada.readUTF();
            boolean existe = existeArchivoCompleto(nombrearchivo, nombreusuario);
            salida.writeBoolean(existe);
            if (existe) {
                cantidadDescargada = entrada.readLong();

                File f = new File(ruta + nombrearchivo);
                tamano = f.length();

                archivo = new FileInputStream(ruta + nombrearchivo);

                if (cantidadDescargada != 0) {
                    archivo.skip(cantidadDescargada);
                }

                System.out.println("Iniciando transmision con" + String.valueOf(archivo.getChannel().size()) + " bytes");
                byte[] buffer = new byte[1024];
                int len;
                int total = 0;
                while ((len = archivo.read(buffer)) > 0) {
                    salida.write(buffer, 0, len);
                    total = total + len;
                }
                System.out.println("Fin de envio");
            }
        } catch (IOException e) {
            System.out.println("se cayo en continuar la descarga");
        }
    }
    /*
     * metodo que se encarga de recibir un archivo del cliente desde cero
     */
    public void cargarArchivo() {
        try {
            String nombreUsuario = entrada.readUTF();
            String nombreArchivo = entrada.readUTF();
            long tamanoEntrada = entrada.readLong();
            File f = new File(ruta + nombreArchivo);
            archivoEntrada = new FileOutputStream(f);
            byte[] buffer = new byte[1024];
            int len;
            int total = 0;
            while ((len = entrada.read(buffer)) > 0) {
                archivoEntrada.write(buffer, 0, len);
                total = total + len;
                if (total == tamanoEntrada) {
                    break;
                }
            }
            archivoEntrada.flush();
            archivoEntrada.close();
            int posicion = posicionUsuario(nombreUsuario);
            Archivo archivoN = new Archivo(nombreArchivo);
            listaPersonas.getMisPersonas().get(posicion).getListaArchivos().add(archivoN);
            salida.writeUTF(cadenaArchivosUsuario(nombreUsuario));
            carga.escribirPersonas(listaPersonas);
        } catch (Exception e) {
            System.out.println("se cayo en la carga");
        }
    }
    /*
     * metodo que se encarga de recibir un archivo del cliente desde un estado especifico
     */
    public void continuarCargarArchivo() {
        try {
            String nombreUsuario = entrada.readUTF();
            String nombreArchivo = entrada.readUTF();
            long tamanoEntrada = entrada.readLong();
            File f = new File(ruta + nombreArchivo);
            salida.writeLong(f.length());
            archivoEntrada = new FileOutputStream(f, true);
            byte[] buffer = new byte[1024];
            int len;
            long total = f.length();
            while ((len = entrada.read(buffer)) > 0) {
                archivoEntrada.write(buffer, 0, len);
                total = total + len;
                if (total == tamanoEntrada) {
                    break;
                }
            }
            archivoEntrada.flush();
            archivoEntrada.close();
            int posicion = posicionUsuario(nombreUsuario);
            Archivo archivoN = new Archivo(nombreArchivo);
            listaPersonas.getMisPersonas().get(posicion).getListaArchivos().add(archivoN);
            salida.writeUTF(cadenaArchivosUsuario(nombreUsuario));
            carga.escribirPersonas(listaPersonas);
        } catch (Exception e) {
            System.out.println("se cayo en continuar la carga");
        }
    }
    /*
     * metodo que se encarga de iniciar el hilo de la clase
     */
    public void run() {
        try {
            entrada = new DataInputStream(socketServicio.getInputStream());
            salida = new DataOutputStream(socketServicio.getOutputStream());
            String tipo = entrada.readUTF();
            if (tipo.equals("LOGIN")) {
                conexionLogin();
            } else if (tipo.equals("CARGA")) {
                cargarArchivo();
            } else if (tipo.equals("CONTINUAR CARGA")) {
                continuarCargarArchivo();
            } else if (tipo.equals("DESCARGA")) {
                descargarArchivo();
            } else if (tipo.equals("CONTINUAR DESCARGA")) {
                continuarDescargarArchivo();
            }
            socketServicio.close();
        } catch (IOException ex) {
            System.out.println("algo en servicio fallo");
        }

    }
}
